package main

import "fmt"

// 常量声明：
const finalValue string = "i am global final value"
const PI float64 = 3.1415
const u, v = 1, "2"
const (
	haha string = "haha"
	lala        = 1
)

// iota为特殊的常量，在每个const时被初始化为0，接着每出现1次，自增1
const (
	c1 = iota // 0
	c2 = iota // 1
	c3 = iota // 2
)

// 如果多个const赋值相同，则可以省略后面的赋值
const (
	y1 = iota
	y2
	y3
)

// 枚举，就把常量当做枚举用嘛 只不过安装go标准，首字母大写的可以导出使用，小写的无法导出，只能当前包使用
const (
	Sunday = iota
	Monday
	Tuesday
	wednesday
)
const (
	test0 = iota
	test2
	test3 = iota
)

func main() {
	//test1()
	//simpleX()
	defaultValue()
	//point()
	//x := 1
	//fmt.Println(&x)
	//valueTransfer(x)
	//pointerTransfer(&x)

	fmt.Println(test0)
	fmt.Println(test2)
	fmt.Println(test3)
	//fmt.Println(finalValue)
}

func test1() {
	var a string = "aa"
	fmt.Println(a)

	// 如果右值已经赋值了，则不需要指定数据类型
	var te = "te"
	fmt.Println(te)

	// 先声明
	var b string
	b = "v"
	fmt.Println(b)

	// 声明多个变量
	var c, d, e string = "c", "d", "e"
	fmt.Println(c, d, e)

	// 快捷方式声明
	var (
		quick1 = "q1"
		quick2 = "q2"
	)
	fmt.Println(quick1)
	fmt.Println(quick2)

	// 多重赋值
	i := 1
	j := 2
	i, j = j, i // 交换i和j两个变量值
	fmt.Println(i)
	fmt.Println(j)
}

/**
默认值
*/
func defaultValue() {
	//0
	var a int
	//0
	var b int32
	//0
	var c int64
	//0
	var d float64
	//空字符""
	var e string
	//false
	var f bool
	//0
	var g byte
	fmt.Printf("%v %v %v %v %v %v", a, b, c, d, e, f)
	fmt.Println(g)

	if e == "" {
		fmt.Println("e is empty")
	}
}

/**
简短声明 只能在函数中才能使用
一般约定：1. 函数内使用:=简短声明
2. 函数外省略类型 var globalValue = "global"
*/
func simpleX() {
	x := "x"
	v := true
	q := 1
	e := 3
	fmt.Println(x)
	fmt.Println(v)
	fmt.Println(q)
	fmt.Println(e)

	// 所有声明方式
	var t string = "t"
	var t1 = "t1"
	t2 := "t3"
	var t4 string
	t4 = "t4"
	fmt.Println(t)
	fmt.Println(t1)
	fmt.Println(t2)
	fmt.Println(t4)
}

// 作用域同Java

// 指针

func point() {
	var s = "s"
	fmt.Println("s在内存中的地址为：")
	fmt.Println(&s)
}

/**
值传递 函数内的变量分配了新的地址
*/
func valueTransfer(x int) {
	println(&x)
}

/**
指针传递
*/
func pointerTransfer(x *int) {
	// x本身就是指针，不需要添加"&"符号：&x
	// 打印出的地址和传递前的地址相同，说明指向原来的地址
	fmt.Println(x)

	//如果要取指针x指向的变量的值，则要添加 * 星号
	//1
	fmt.Println(*x)
	return
}

/*
TODO https://studygolang.com/articles/35220
TODO 在Go语言中只存在值传递，要么是值的副本，要么是指针的副本。无论是值类型的变量还是引用类型的变量亦或是指针类型的变量作为参数传递都会发生值拷贝，
TODO 开辟新的内存空间。另外值传递、引用传递和值类型、引用类型是两个不同的概念。引用类型作为变量传递可以影响到函数外部是因为发生值拷贝后新旧变量指向了相同的内存地址。
*/
